package main.java.edu.cg1.exercises.introduction;

import java.util.Timer;

import javax.media.j3d.Group;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;

import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Cylinder;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Aufgabe1 extends CG1Frame {

    private TransformGroup superTransformerManGroup;
    private Transform3D superTransformerMan;

    /* Create the default scene graph.
     */
    @Override
    protected void createSceneGraph() {
    	// Set the view position back far enough so that we can see things
        TransformGroup viewTransform = universe.getViewingPlatform().getViewPlatformTransform();
        Transform3D t3d = new Transform3D();
        t3d.lookAt(new Point3d(10,10,20), new Point3d(0,0,0), new Vector3d(0,1,0));
        t3d.invert();
        viewTransform.setTransform(t3d);
    	
    	addLight(universe);

        for (double x = -8; x < 10; x += 2) {
            for (double z = -8; z < 10; z += 2) {
                if (Math.random() < 0.5) {
                    scene.addChild(createFactory(x, z));
                } else {
                    scene.addChild(createBuilding(x + Math.random(), z + Math.random()));
                }
            }
        }
        Superman superman = new Superman(7, 5, 0);
        Group supermangroup = superman.getMainGroup();
        superTransformerMan = new Transform3D();
        superTransformerManGroup = new TransformGroup(superTransformerMan);
        superTransformerManGroup.addChild(supermangroup);
        superTransformerManGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        scene.addChild(superTransformerManGroup);

        // Starten eines Timers
        Timer timer = new Timer();
        timer.schedule(new AnimateTask(superTransformerManGroup, superman.getRightArmGroup()), 50, 50);
        
        scene.addChild(generateLandscape());
        
        // Assemble scene
        scene.compile();
        universe.addBranchGraph(scene);
    }

    /**
     * Erstellt ein Fabrikgebäude
     * @param x: X Koordinate
     * @param z: Z Koordinate
     * @return Gesamtgruppe des Fabrikgebäudes
     */
    private Group createFactory(double x, double z) {
        Vector3d size = new Vector3d(0.8, 0.25, 0.3);
        
        Box house = new Box();
        AppearanceHelper.setColor(house, new Color3f(0.3f, 0.1f, 0.001f));
        Transform3D scaleHouse = new Transform3D();
        scaleHouse.rotY(Math.random());
        scaleHouse.setScale(size);
        scaleHouse.setTranslation(new Vector3d(x, size.y, z));	
        TransformGroup group1 = new TransformGroup(scaleHouse);
        group1.addChild(house);

        Cylinder cylinder = new Cylinder(0.1f, 0.5f);
        AppearanceHelper.setColor(cylinder, new Color3f(0.3f, 0.1f, 0.001f));
        Transform3D scaleCylinder = new Transform3D();
        scaleCylinder.setTranslation(new Vector3d(x, size.y * 2 + 0.25, z));
        TransformGroup group2 = new TransformGroup(scaleCylinder);
        group2.addChild(cylinder);

        Group group = new Group();
        group.addChild(group1);
        group.addChild(group2);

        return group;
    }

    /**
     * Erstellt ein Hochhaus mit einer Antenne
     * @param x: X Koordinate
     * @param z: Z Koordinate
     * @return Gruppe des Gesmatgebäudes
     */
    private Group createBuilding(double x, double z) {
        Vector3d size = new Vector3d(0.2, 1, 0.4);

        Box house = new Box();
        AppearanceHelper.setColor(house, new Color3f(0.3f, 0.3f, 0.3f));
        Transform3D scaleHouse = new Transform3D();
        scaleHouse.setScale(size);
        scaleHouse.setTranslation(new Vector3d(x, size.y, z));		
        TransformGroup group1 = new TransformGroup(scaleHouse);
        group1.addChild(house);

        Box stairs = new Box();
        AppearanceHelper.setColor(stairs, new Color3f(1f, 1f, 1f));
        Transform3D scaleStairs = new Transform3D();
        scaleStairs.setScale(new Vector3d(0.05, 0.05, 0.1));
        scaleStairs.setTranslation(new Vector3d(x, size.y * 2 + 0.05, z));
        TransformGroup group2 = new TransformGroup(scaleStairs);
        group2.addChild(stairs);

        Cylinder cylinder = new Cylinder(0.01f, 1f);
        AppearanceHelper.setColor(cylinder, new Color3f(1f, 0f, 0f));
        Transform3D scaleCylinder = new Transform3D();
        scaleCylinder.setTranslation(new Vector3d(x, size.y * 2 + 0.5, z));
        TransformGroup group3 = new TransformGroup(scaleCylinder);
        group3.addChild(cylinder);

        Group group = new Group();
        group.addChild(group1);
        group.addChild(group2);
        group.addChild(group3);

        return group;
    }

    /**
     * Setup the lights in the scene. Attention: The light need to be added to
     * the scene before the scene in compiled (see createSceneGraph()).
     */
    private void addLight(SimpleUniverse universe) {
        addPointLight(new Point3f(5, 5, 5));
        addPointLight(new Point3f(-5, 5, -5));
        addPointLight(new Point3f(0, 5, 0));
    }

    /**
     * Erstellt die Landschaft auf der die Häuser stehen. Reflektiert nicht
     * @return Landschaftsgruppe
     */
    private Group generateLandscape() {
        Vector3d size = new Vector3d(10, 0.01, 10);

        Transform3D scale = new Transform3D();
        Box box = new Box();
        AppearanceHelper.setNoReflectionColor(box, new Color3f(0.1f, 0.1f, 0.1f));
        scale.setScale(size);
        TransformGroup group = new TransformGroup(scale);
        group.addChild(box);

        return group;
    }

    /**
     * Program entry point.
     */
    public static void main(String[] args) {
        // Create the central frame
        Aufgabe1 frame = new Aufgabe1();
        // Add content to the scene graph
        frame.createSceneGraph();
    }
}
